package com.ywu.standard.gateway.service;

import com.ywu.boot.context.YwuContext;
import com.ywu.standard.gateway.config.AppConfig;
import com.ywu.standard.gateway.data.YwuGatewayApiRecordRepository;
import com.ywu.standard.gateway.entity.GatewayApiEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @ClassName GatewayApiRedisCacheService
 * @Description 网关请求接口状态缓存
 * @Author GroundDemo
 * @Date 2025/3/24 10:25
 * @Version 1.0
 **/
@Service
@Slf4j
public class GatewayApiRecordService {

    @Autowired
    private AppConfig appConfig;

    @Autowired
    private YwuGatewayApiRecordRepository recordRepository;

    @Autowired
    private StringRedisTemplate redisTemplate;

    private final List<GatewayApiEntity> entityList = new ArrayList<>();

    private final ReentrantLock lock = new ReentrantLock();

    // 日活
    private static final String REDIS_DAY_PV_KEY = "YWU_PV_KEY:DAY_GROUP:";

    // 月活
    private static final String REDIS_MONTH_PV_KEY = "YWU_PV_KEY:MONTH_GROUP:";

    private static final String REDIS_DAY_UV_KEY = "YWU_UV_KEY:DAY_GROUP:";

    // 月活
    private static final String REDIS_MONTH_UV_KEY = "YWU_UV_KEY:MONTH_GROUP:";

    /**
    * @Author GroundDemo
    * @Description 定时任务进行定时入库
    * @Date 10:49 2025/3/24
    * @Param []
    * @return void
    **/
    @Scheduled(fixedRateString = "${ywu.gateway.apiRedisCacheInternal:60000}")
    public void scheduleRecord() {
        lock.lock();
        try {
            doRepository();
        } catch (Exception e) {
            log.error("scheduleRecord error {}", e.getMessage());
        } finally {
            lock.unlock();
        }
    }

    /**
    * @Author GroundDemo
    * @Description 添加API访问记录
    * @Date 10:40 2025/3/24
    * @Param [entity, ywuContext]
    * @return void
    **/
    @Async
    public void addApiRecord(GatewayApiEntity entity, YwuContext ywuContext) {
        // 记录PV信息
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        simpleDateFormat.setTimeZone(TimeZone.getTimeZone("GMT+8"));
        String formatDate = simpleDateFormat.format(date);
        // 记录PV日活
        incrementRedisKey(REDIS_DAY_PV_KEY + formatDate, 1, 10);

        // 记录PV月活
        int lastIndex = formatDate.lastIndexOf("-");
        String monthFormat = formatDate.substring(0, lastIndex);
        incrementRedisKey(REDIS_MONTH_PV_KEY + monthFormat, 1, 10 * 31);
        // 记录UV日活
        redisTemplate.opsForHyperLogLog().add(REDIS_DAY_UV_KEY + formatDate, ywuContext.getYwuContextUser().getUserAccount());
        redisTemplate.expire(REDIS_DAY_UV_KEY + formatDate, 10, TimeUnit.DAYS);
        redisTemplate.opsForHyperLogLog().add(REDIS_MONTH_UV_KEY + monthFormat, ywuContext.getYwuContextUser().getUserAccount());
        redisTemplate.expire(REDIS_MONTH_UV_KEY + monthFormat, 10 * 31, TimeUnit.DAYS);
        entity.createInfo("gateway");
        entity.updateInfo("gateway");
        lock.lock();
        try {
            if (entityList.size() < appConfig.getApiRedisCacheMaxSize()) {
                // 数组存放没有满，直接插入数组
                entityList.add(entity);
            } else {
                // 执行数据入库
                doRepository();
                entityList.add(entity);
            }
        } catch (Exception e) {
            log.error("addApiRecord error {}", e.getMessage());
        } finally {
            lock.unlock();
        }
    }

    /**
    * @Author GroundDemo
    * @Description 执行数据入库方法
    * @Date 10:47 2025/3/24
    * @Param []
    * @return void
    **/
    private void doRepository() {
        if (this.entityList.size() == 0) {
            return;
        }
        recordRepository.addApiRecordBatch(this.entityList);
        this.entityList.clear();
    }

    /**
    * @Author GroundDemo
    * @Description 自增redis中的值
    * @Date 11:45 2025/3/24
    * @Param [key, hashKey, incr]
    * @return void
    **/
    private void incrementRedisKey(String key, long incr, int expireDays) {
        Object getDayPvKey = redisTemplate.opsForValue().get(key);
        if (Objects.isNull(getDayPvKey)) {
            // 设置参数
            redisTemplate.opsForValue().set(key, "1");
            // 设置超时时间
            redisTemplate.expire(key, expireDays, TimeUnit.DAYS);
        } else {
            // 自增参数
            redisTemplate.opsForValue().increment(key, incr);
        }
    }
}
